package org.xtense.engine;

import java.io.File;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xtense.log.iLog;
import org.xtense.model.CAttribute;
import org.xtense.model.CDocument;
import org.xtense.model.CElement;
import org.xtense.model.CText;
import org.xtense.model.PathEntry;
import org.xtense.util.StringUtil;

public class XmlFileReader implements IXmlReader {

	/**
	 * The file path of the xml file to be open.
	 */
	private String filePath;

	/**
	 * Used to generate elementPre for an element. Once its value is used to
	 * record an element, it will increment.
	 */
	private int elementPreGen = 1;
	
	private CDocument cDocument;

	/**
	 * Default Constructor
	 */
	public XmlFileReader() {

	}

	/**
	 * 
	 * @param filePath
	 */
	public XmlFileReader(String filePath) {
		super();
		this.filePath = filePath;
	}

	/**
	 * getter method
	 * 
	 * @return the filePath attribute
	 */
	public String getFilePath() {
		return filePath;
	}

	/**
	 * setter method
	 * 
	 * @param filePath
	 *            the file path of the xml file you want to get.
	 */
	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}

	/**
	 * Open default xml file. Default file path is stored in filePath attribute.
	 * 
	 * @return CDocument description of this file.
	 */
	public CDocument read() {
		return this.read(this.filePath);
	}

	/**
	 * 
	 * @param filePath
	 * @return
	 */
	public CDocument read(String filePath) {
		iLog.info("Reading from the path:" + filePath);
		elementPreGen = 1;

		File f = new File(filePath);
		SAXReader reader = new SAXReader();
		Document doc = null;
		cDocument = new CDocument(f.getName());
		try {
			doc = reader.read(f);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// get root element
		Element root = doc.getRootElement();

		// use goThroughElements() to go through the xml file, store
		// elements, attributes, texts in cElements, cAttributes, cTexts.
		// The parentpre of the root element is 0.
		goThroughElements(root, 0);
		
		iLog.info("Reading finished.");
		

		return cDocument;
	}

	/**
	 * 
	 * @param e
	 * @param parentPre
	 */
	@SuppressWarnings("unchecked")
	private void goThroughElements(Element e, int parentPre) {
		// create a CElement object and put the object into the cElements
		// collection.
		CElement cElement = new CElement(elementPreGen++, e.getName(),
				parentPre);
		cDocument.addElement(cElement);
		
		//add the xpath expression of current element.
		//StringUtil.changeDelimiter(String) is used to change "/" to "#/" and "//" to "#%/"
		cDocument.addPath(new PathEntry(cElement.getElementPre(), StringUtil
				.changeDelimiter(e.getPath())));

		// If current element has attribute(s)
		if (e.attributeCount() > 0) {
			// get all its attributes and put them in a list of type
			// Attribute.
			List<Attribute> eAttributes = e.attributes();

			// fill eCAttributes.
			for (int i = 0; i < eAttributes.size(); i++)
				cDocument.addAttribute(new CAttribute(cElement.getElementPre(),
						eAttributes.get(i).getName(), eAttributes.get(i)
								.getStringValue()));
		}

		// If current element contains text
		if (e.getTextTrim().length() != 0) {
			CText cText = new CText(cElement.getElementPre(), e.getTextTrim());
			cDocument.addText(cText);
		}

		// Then go to its child elements
		List<Element> childElements = e.elements();
		for (int j = 0; j < childElements.size(); j++)
			goThroughElements(childElements.get(j), cElement.getElementPre());
	}

}
